package com.baijia.commons.util;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.StatusLine;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.map.JsonMappingException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.baijia.commons.lang.utils.file.FileUtils;
import com.google.common.collect.Maps;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

/**
 * 
 * @title HttpClientUtils
 * @desc TODO
 * @author wangzhigang
 * @date 2014年10月17日
 * @version 1.0
 */
public class HttpClientUtil {

    private static final Logger logger = LoggerFactory.getLogger(HttpClientUtil.class);

    // private static final CloseableHttpClient httpClient;
    public static final String CHARSET = "UTF-8";

    public static CloseableHttpClient getHttpClient() {
        RequestConfig config = RequestConfig.custom().setConnectTimeout(20000).setSocketTimeout(20000).build();
        // RequestConfig config = RequestConfig.custom().setConnectTimeout(60000).setSocketTimeout(35000).build();
        return HttpClientBuilder.create().setDefaultRequestConfig(config).build();
    }

    public static String doGet(String url, Map<String, String> params) {
        return doGet(url, params, CHARSET, null);
    }

    public static String doGet(String url, Map<String, String> params, Collection<Header> headers) {
        return doGet(url, params, CHARSET, headers);
    }

    public static String doPost(String url, Map<String, String> params) {
        try {
            logger.info("doPost.url:{}, params:{}", url, JacksonUtil.obj2Str(params));
        } catch (IOException e) {
            e.printStackTrace();
        }
        return doPost(url, params, CHARSET, null);
    }

    public static String doPost(String url, Map<String, String> params, Collection<Header> headers) {
        try {
            logger.info("doPost.url:{}, params:{}", url, JacksonUtil.obj2Str(params));
        } catch (IOException e) {
            e.printStackTrace();
        }
        return doPost(url, params, CHARSET, headers);
    }

    /**
     * HTTP Get 获取内容
     * 
     * @param url 请求的url地址 ?之前的地址
     * @param params 请求的参数
     * @param charset 编码格式
     * @return 页面内容
     */
    public static String doGet(String url, Map<String, String> params, String charset) {
        return doGet(url, params, charset, null);
    }
    public static String doGet(String url, Map<String, String> params, String charset, Collection<Header> headers) {
        if (StringUtils.isBlank(url)) {
            return null;
        }
        try {
            if (params != null && !params.isEmpty()) {
                List<NameValuePair> pairs = new ArrayList<NameValuePair>(params.size());
                for (Map.Entry<String, String> entry : params.entrySet()) {
                    String value = entry.getValue();
                    if (value != null) {
                        pairs.add(new BasicNameValuePair(entry.getKey(), value));
                    }
                }
                url += "?" + EntityUtils.toString(new UrlEncodedFormEntity(pairs, charset));
            }
            HttpGet httpGet = new HttpGet(url);
            if (CollectionUtils.isNotEmpty(headers)) {
                for (Header header : headers) {
                    httpGet.addHeader(header);
                }
            }
            CloseableHttpClient httpClient = getHttpClient();

            CloseableHttpResponse response = httpClient.execute(httpGet);
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode != 200) {
                httpGet.abort();
                throw new RuntimeException("HttpClient,error status code :" + statusCode);
            }
            HttpEntity entity = response.getEntity();
            String result = null;
            if (entity != null) {
                result = EntityUtils.toString(entity, "utf-8");
            }
            EntityUtils.consume(entity);
            response.close();
            return result;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * HTTP Post 获取内容
     * 
     * @param url 请求的url地址 ?之前的地址
     * @param params 请求的参数
     * @param charset 编码格式
     * @return 页面内容
     */
    public static String doPost(String url, Map<String, String> params, String charset) {
        return doPost(url, params, charset, null);
    }
    public static String doPost(String url, Map<String, String> params, String charset, Collection<Header> headers) {
        if (StringUtils.isBlank(url)) {
            return null;
        }
        try {
            List<NameValuePair> pairs = null;
            if (params != null && !params.isEmpty()) {
                pairs = new ArrayList<NameValuePair>(params.size());
                for (Map.Entry<String, String> entry : params.entrySet()) {
                    String value = entry.getValue();
                    if (value != null) {
                        pairs.add(new BasicNameValuePair(entry.getKey(), value));
                    }
                }
            }
            HttpPost httpPost = new HttpPost(url);
            if (pairs != null && pairs.size() > 0) {
                httpPost.setEntity(new UrlEncodedFormEntity(pairs, CHARSET));
            }

            if (CollectionUtils.isNotEmpty(headers)) {
                for (Header header : headers) {
                    httpPost.addHeader(header);
                }
            }

            CloseableHttpClient httpClient = getHttpClient();
            CloseableHttpResponse response = httpClient.execute(httpPost);
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode != 200) {
                httpPost.abort();
                throw new RuntimeException("HttpClient,error status code :" + statusCode);
            }
            HttpEntity entity = response.getEntity();
            String result = null;
            if (entity != null) {
                result = EntityUtils.toString(entity, "utf-8");
            }
            EntityUtils.consume(entity);
            response.close();
            return result;
        } catch (Exception e) {
            logger.error("post error", e);
        }
        return null;
    }

    /**
     * 上传文件
     * 
     * @param url
     * @param params
     * @param files
     * @return
     */
    public static String doPost(String url, Map<String, String> params, Map<String, File> files) {
        CloseableHttpResponse response = null;
        try {
            logger.trace("doPost - start, url:{}", url);

            long start = System.currentTimeMillis();
            RequestConfig config = RequestConfig.custom().setConnectTimeout(10000).setSocketTimeout(60000).build();
            CloseableHttpClient httpClient = HttpClientBuilder.create().setDefaultRequestConfig(config).build();
            long end = System.currentTimeMillis();
            logger.info("HttpClientUtils.doPost: get httpClinet, cost:{}", (end - start));

            HttpPost httpPost = new HttpPost(url);
            MultipartEntity multipartEntity = new MultipartEntity();

            long getPostTime = System.currentTimeMillis();
            logger.info("HttpClientUtils.doPost: getHttppOST cost:{}", (getPostTime - end));
            // add files
            for (Map.Entry<String, File> file : files.entrySet()) {
                multipartEntity.addPart(file.getKey(), new FileBody(file.getValue()));
            }

            // add params
            for (Map.Entry<String, String> param : params.entrySet()) {
                multipartEntity.addPart(param.getKey(), new StringBody(param.getValue()));
            }

            httpPost.setEntity(multipartEntity);
            logger.trace("doPost - execute, url:{}", url);
            response = httpClient.execute(httpPost);
            StatusLine status = response.getStatusLine();
            logger.trace("doPost - execute end, url:{}, status:{}", url, status);

            HttpEntity responseEntity = response.getEntity();
            String responseCont = EntityUtils.toString(responseEntity, CHARSET);
            EntityUtils.consume(responseEntity);
            logger.debug("doPost - url:{}, status:{}, response:{}", url, status, responseCont);

            return responseCont;
        } catch (Exception e) {
            throw new RuntimeException("dopost exception - ", e);
        }
    }

    public static void main(String[] args) throws JsonGenerationException, JsonMappingException, IOException,
        InterruptedException {
        Map<String, String> params = Maps.newHashMap();
        params.put("org_id", "1");
        params.put("total_prices", "100");
        String url = "http://test-pay.genshuixue.com/purchase/createOrgSinupPurchase";
        System.out.println(doPost(url, params));
    }

    public static String doJsonPost(String url, Object params, String charset) throws Exception {
        GsonBuilder builder = new GsonBuilder().disableHtmlEscaping();
        Gson gson = builder.create();

        String jsonPost = null;
        if (params instanceof String) {
            jsonPost = (String) params;
        } else {
            jsonPost = gson.toJson(params);
        }
        logger.info("url:{}, jsonPost:{}", url, jsonPost);

        HttpPost httpPost = new HttpPost(url);
        StringEntity requestEntity = new StringEntity(jsonPost, CHARSET);
        requestEntity.setContentType("application/json");
        requestEntity.setContentEncoding(CHARSET);
        httpPost.setEntity(requestEntity);

        CloseableHttpClient httpClient = getHttpClient();
        CloseableHttpResponse response = httpClient.execute(httpPost);
        try {
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode != 200) {
                httpPost.abort();
                throw new RuntimeException("HttpClient,error status code :" + statusCode);
            }
            HttpEntity responseEntity = response.getEntity();
            String result = null;
            if (responseEntity != null) {
                result = EntityUtils.toString(responseEntity, charset);
            }
            EntityUtils.consume(responseEntity);
            return result;
        } finally {
            if (response != null) {
                response.close();
            }
        }
    }

    public static byte[] download(String url) throws Exception {
        try {
            HttpGet httpGet = new HttpGet(url);
            CloseableHttpClient httpClient = getHttpClient();
            CloseableHttpResponse response = httpClient.execute(httpGet);
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode != 200) {
                httpGet.abort();
                throw new IllegalStateException("download - error status code :" + statusCode);
            }

            HttpEntity entity = response.getEntity();
            byte[] result = FileUtils.readBytes(entity.getContent());
            EntityUtils.consume(entity);
            response.close();
            return result;
        } catch (Exception e) {
            logger.warn("download exception - ", e);
            return null;
        }
    }
}
